package org.ansel.webnodb.demo.service;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;
import org.ansel.webnodb.demo.beans.WebnodbProps;
import org.ansel.webnodb.demo.utils.AnselHttpsClientUtil;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


@Service
public class IpService {
	private static final Logger logger = LoggerFactory.getLogger(IpService.class);
	/** 翻墙订阅地址。
	 */
	@Autowired
	private WebnodbProps props;

	/** 查询服务器当前适配的公网ip
	 * @return
	 */
	public String getPublicIp() {
		String ip="";
		//读取公网ip的接口地址
		//http://ip-api.com/json/  query字段
		//https://api.ip.sb/geoip  ip字段
		//https://6.ipw.cn/获取IPv6或者https://4.ipw.cn/获取IPv4 最快
		String url="https://api.ip.sb/geoip";
		org.ansel.webnodb.demo.utils.AnselHttpsClientUtil httpClient = new org.ansel.webnodb.demo.utils.AnselHttpsClientUtil();
		String ipres="";
		try {
			logger.info(ipres);
			ipres=httpClient.httpget(url);
			logger.info(ipres);
			JSONObject j = (JSONObject) JSONObject.parse(ipres);
			ip=j.getString("ip");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("getPublicIp error.",e);
		}
		return ip;
	}

	@Deprecated
	public String getDomainIp(String domainname) {
		try {
            InetAddress[] addresses = InetAddress.getAllByName(domainname);
            for (int i = 0; i < addresses.length; i++) {
            	logger.info(domainname + "[" + i + "]: " + addresses[i].getHostAddress());
            }
        } catch (UnknownHostException uhe) {
        	uhe.printStackTrace();
        	logger.error("Unable to find: " + domainname);
        }
		return "";
	}
	
	/** 订阅地址。根据当前时间减去12小时作为订阅日期，查询订阅地址的代理服务节点。
	 * @param urlTpl 网址模板，参数用#YEAR#、#MONTH#、#DATE#表示。
	 * @return 返回BASE64长文本。
	 */
	public String getCommonNodes(String urlTpl) {
		//当前时间回退12小时，防止网站没有生成当时的文件。
		DateFormat df = new SimpleDateFormat("yyyyMMdd");
		Date now=new Date();
		Date calcday=new Date(now.getTime()-12*3600*1000);
		String daystr=df.format(calcday);
		String ystr=daystr.substring(0,4);
		String mstr=daystr.substring(4,6);
		String nodefreeurl=urlTpl;
		nodefreeurl=nodefreeurl.replace("#YEAR#",ystr);
		nodefreeurl=nodefreeurl.replace("#MONTH#",mstr);
		nodefreeurl=nodefreeurl.replace("#DATE#",daystr);
		logger.info("访问"+nodefreeurl);
		String res="";
		AnselHttpsClientUtil httpClient = new AnselHttpsClientUtil();
		try {
			res=httpClient.httpget(nodefreeurl);
			logger.info(res);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("getCommonNodes error.",e);
		}
		return res;
	}
	/**获取所有免费节点。
	 * @param usonly 是否只获取北美节点。选项1是，0否。
	 * @return
	 */
	public String getFreeNodes(String usonly) {
		String ret = "";
		//1.获取多个来源的免费节点，保存成base64加密字符串
		List<String> base64nodes= new ArrayList<String>();
		String freenodes = "";
		Set<String> nodeurls = this.props.getNodeurls();
		for(String urltpl : nodeurls) {
			freenodes=getCommonNodes(urltpl);
			base64nodes.add(freenodes);
		}
		//2.将多个base64字符串解码，并拼接成新的长字符串明文。
		byte[] tmp;
		for(String base64str : base64nodes) {
			tmp=Base64.decodeBase64(base64str);
			String nodesstr=new String (tmp);
			ret+=System.lineSeparator()+nodesstr;
		}
		if("1".equals(usonly)) {
			ret=getFreeNodes_usonly(ret);
		}
		//3.将新长字符串进行base64加密
		tmp=Base64.encodeBase64(ret.getBytes());
		ret=new String(tmp);
		logger.info("getFreeNodes returns "+ret);
		return ret;
	}
	/** 从原始节点字符串中截取北美节点。即备注中包含美国或加拿大字样。
	 * @param origstr 原始节点字符串，明文，可直接复制导入软件的格式。
	 * @return
	 */
	private String getFreeNodes_usonly(String origstr) {
		/* 一般情况下vmess协议链接中是base64解密，解密后显示json字符串，中文为unicode编码%格式。其他协议用#标识备注，中文用uriencode加密成\\u格式。
		 */
		BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(origstr.getBytes())));  
		Set<String> retlist = new HashSet<String>();
		String line;
		int nodealllength=0;
		try {
			while ((line = br.readLine()) != null) {
				if("".equals(line.trim())) {
					continue;
				}
				nodealllength++;
				if (retlist.contains(line)) {
					continue;
				}
				String tmp = line;
				if (line.startsWith("vmess://")) {
					// 格式：vmess://eyJhZGQiOiIxMjQuMjIwLjU3Ljc1IiwiYWlkIjowLCJpZCI6IjFiM2RkOTViLWY2ZGMtNGYyMC05N2FhLTNiMzY1MzU4NDE5YyIsIm5ldCI6InRjcCIsInBhdGgiOiIvIiwicG9ydCI6ODAsInBzIjoiXHVEODNDXHVEREU4XHVEODNDXHVEREYzX0NOX1x1NEUyRFx1NTZGRCIsInRscyI6IiIsInYiOjJ9
					tmp = line.replace("vmess://", "");
					tmp = new String(Base64.decodeBase64(tmp));
				}
				if (this.getFreeNodes_usonly4Chinease(tmp)) {
					retlist.add(line);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("getFreeNodes_usonly error.",e);
		} 
		logger.info("getFreeNodes_usonly nodealllength="+nodealllength);
		logger.info("getFreeNodes_usonly node.size()="+retlist.size());
		String ret = String.join(System.lineSeparator(), retlist);
		return ret;
	}
	/** 对节点字符串变换多种中文编码格式,判断节点字符串备注中是否包含美国或加拿大字样。
	 * @param nodestr 个节点的字符串，明文
	 * @return
	 */
	private boolean getFreeNodes_usonly4Chinease(String nodestr) {
		logger.debug("getFreeNodes_usonly4Chinease node string is: "+nodestr);
		if (nodestr.contains("\\u7f8e\\u56fd") || nodestr.contains("美国") || nodestr.contains("%E7%BE%8E%E5%9B%BD")||nodestr.contains("_US_")
				|| nodestr.contains("\\u52a0\\u62ff\\u5927") || nodestr.contains("加拿大")|| nodestr.contains("%E5%8A%A0%E6%8B%BF%E5%A4%A7")) 
		{
			logger.debug("getFreeNodes_usonly4Chinease node  "+"orig_true");
			return true;
		}
		String[] charsets = new String[] { "UTF-8", "GB2312", "GBK" };
		for (String chari : charsets) {
			try {
				nodestr = new String(nodestr.getBytes(), chari);
				if (nodestr.contains("\\u7f8e\\u56fd") || nodestr.contains("美国")|| nodestr.contains("%E7%BE%8E%E5%9B%BD") 
						|| nodestr.contains("\\u52a0\\u62ff\\u5927")|| nodestr.contains("加拿大") || nodestr.contains("%E5%8A%A0%E6%8B%BF%E5%A4%A7")) 
				{
					logger.debug("getFreeNodes_usonly4Chinease node  "+chari+"_true");
					return true;
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				logger.error("解析字符串失败。", e);
			}
		}
		logger.debug("getFreeNodes_usonly4Chinease node "+"UTF-8, GB2312, GBK_false;");
		return false;
	}
	public static void main(String[] args) {
		IpService service = new IpService();
	}
}

